package com.itheima.search.service.impl;

import com.itheima.common.pojo.PageInfo;
import com.itheima.common.util.RequestContext;
import com.itheima.search.dao.ArticleDao;
import com.itheima.search.document.ArticleInfoDocument;
import com.itheima.search.dto.SearchDto;
import com.itheima.search.service.ApUserSearchService;
import com.itheima.search.service.SearchService;
import com.itheima.search.task.SyncKeyword;
import org.bouncycastle.cert.ocsp.Req;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * @Author：shenkunlin
 * @date： 2021/9/2 11:57
 * @Description：
 ***/
@Service
public class SearchServiceImpl implements SearchService {

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Autowired
    private ArticleDao articleDao;

    @Autowired
    private ApUserSearchService apUserSearchService;

    //线程池
    private static ExecutorService pool = new ThreadPoolExecutor(
            10,
            15,
            1000,
            TimeUnit.MILLISECONDS,
            new SynchronousQueue<Runnable>(),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.AbortPolicy());

    /****
     * 搜索实现
     * 查询->关键词搜索
     *   A:搜索->封装搜索条件对象XxxQuery,封装搜索条件
     *   B:配置高亮域->指定高亮域、指定高亮的前缀、后缀
     *   C:分页搜索
     *   D:解析结果集
     *        1:非高亮数据
     *        2:高亮数据
     *        3:将非高亮数据替换成高亮数据
     */
    @Override
    public PageInfo<ArticleInfoDocument> search(SearchDto dto) {
        /***
         * 记录关键词
         * apUserSearchService.saveSearch(dto);
         *  1）创建一个线程池
         *  2）每次调用搜索的时候，都开启一个线程，交给线程池管理
         */
        //pool.execute(new Runnable() {
        //    @Override
        //    public void run() {
        //        apUserSearchService.saveSearch(dto);
        //    }
        //});
        Integer userId = RequestContext.getNodeValue("id");
        if(userId!=null){
            dto.setUserId(userId);
        }
        String token = RequestContext.getNode("token");
        Map<String,Object> dataMap = new HashMap<String,Object>();
        dataMap.put("token",token);
        dataMap.put("dto",dto);
        pool.execute(new SyncKeyword(dataMap));

        //A:搜索->封装搜索条件对象XxxQuery,封装搜索条件
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder(); //封装搜索条件
        if(!StringUtils.isEmpty(dto.getKeywords())){
            //搜索条件构建起 QueryBuilders
            queryBuilder.withQuery(QueryBuilders.matchQuery("title",dto.getKeywords()));
        }

        //B:配置高亮域->指定高亮域、指定高亮的前缀、后缀
        queryBuilder.withHighlightFields(
                new HighlightBuilder
                        .Field("title")
                        .preTags("<span>")
                        .postTags("</span>")
        );

        //C:分页、排序、搜索
        //queryBuilder.withSort(new FieldSortBuilder("likes").order(SortOrder.DESC));
        queryBuilder.withSort(SortBuilders.fieldSort("likes").order(SortOrder.DESC));
        queryBuilder.withPageable(PageRequest.of(dto.getPage()-1,dto.getSize()));
        //搜索
        SearchHits<ArticleInfoDocument> hits = elasticsearchRestTemplate.search(queryBuilder.build(), ArticleInfoDocument.class);

        //D:解析结果集
        List<ArticleInfoDocument> articles = new ArrayList<ArticleInfoDocument>();
        for (SearchHit<ArticleInfoDocument> hit : hits) {
            //     1:非高亮数据
            ArticleInfoDocument article = hit.getContent();

            //     2:高亮数据
            List<String> titles = hit.getHighlightField("title");

            //     3:将非高亮数据替换成高亮数据
            if(titles.size()>0){
                String title = titles.toString().replace("[","").replace("]","");
                article.setTitle(title);
            }
            articles.add(article);
        }

        Long total = hits.getTotalHits();
        Long pages = total%dto.getSize()==0? total/dto.getSize() : total/dto.getSize()+1;
        PageInfo<ArticleInfoDocument> pageInfo = new PageInfo<ArticleInfoDocument>(dto.getPage().longValue(),dto.getSize().longValue(),total,pages,articles);
        return pageInfo;
    }

    @Override
    public void saveToEs(ArticleInfoDocument document) {
        articleDao.save(document);
    }

}
